## @package auto_utility
#  Module auto_utility - set of different usefull functions. @author Ivan Filippov (filippov@paragon-software.com)
#
#  @file auto_utility.py source file for module auto_utility
import os
import auto_log
import re
import shutil
import time


ID_FILES_LIST_FROM_PATH = "files_list_from_path"
ID_SEARCH_STARTUP_FOLDER = "search_startup_folder"
ID_COPY_PYTHON_MODULES = "copy_python_modules"
ID_CHECK_PATHS_EXISTS = "check_paths_exists"
ID_PREPARE = "prepare"
ID_COPY_FOLDER = "copy_folder"
ID_CREATE_RUN_BAT = "create_run_bat"
ID_GET_SYSTEM_DRIVE = "get_system_drive"
ID_ADD_CERTIFICATE = "add_certificate"
ID_FILE_FROM_PATH = "file_from_path"
ID_CALL_DISKPART = "call_diskpart"
ID_HDM_CHANGE_LAYOUT_INI_KEY = "hdm_change_layout_ini_key"
ID_COPY_FILES_LIST = "copy_files_list"

AUTOTEST_RUN = "Autotest_Run"

## <b>Description:</b> The function gets list of certain files from path.
#  
#  The function gets list of certain files from path.
#  In case of success the function returns the dictionary value = {"err": 0, "res": list}.
#  <br>"err" is integer value = 0, "res" is list of certain files. path to each file is ending with certain string - for example 
#  if string is equal to ".exe" - we'll get list of all *.exe files
#  <br>In case of error the function returns the dictionary value = {"err": message, "res": []}<br>
#  "err" is string value with error description, "res" is empty list - [].
#  @param path
#  string value = path
#  @param name
#  string value = certain string - for example if string is equal to ".exe" - we'll get list of all *.exe files
#  @param log
#  string value = path to file for logging. Default value auto_log.LOG_TO_STDOUT - log to stdout. 
#  Also you can use auto_log.LOG_TO_NONE to disable logging.
#  
## <b>Example:</b>
#  <br>@code
#from auto_utility import files_list_from_path
#
#result = files_list_from_path("e:\\VmwareWorkstationsFolder", ".vmx")
#if result["err"] != 0:
#    print("Can't read list of files from path. Error = ", result["err"])
#else:
#    print("List of *.vmx files = ")
#    print(result["res"])
#@endcode
def files_list_from_path(path, name, log = auto_log.LOG_TO_STDOUT):
    id = ID_FILES_LIST_FROM_PATH
    #--------------------------------------------------
    result = check_paths_exists([path])
    if result != 0:
        message = result
        auto_log.write_result(log, message, auto_log.STATUS_ERROR, id)
        result = {"err": message, "res": []}
        return result
    #--------------------------------------------------
    files_list = []
    #--------------------------------------------------
    try:
        for root, dirs, files in os.walk(path):
            for file in files:
                if file.upper().endswith(name.upper()):
                    files_list.append(root + "\\" + file)
    except:
        message = "Can't get list of files ends with: " + name + " from path: " + path
        auto_log.write_result(log, message, auto_log.STATUS_ERROR, id)
        result = {"err": message, "res": []}
        return result
    
    result = {"err": 0, "res": files_list}
    return result
#----------------------------------------------------------------------

## <b>Description:</b> The function gets list of certain files from path.
#  
#  The function gets certain file from path.
#  In case of success the function returns the dictionary value = {"err": 0, "res": file}.
#  <br>"err" is integer value = 0, "res" is path to certain file. 
#  <br>For example path = "c:\\logs", name = "layout.ini". In case of success file_from_path(path, name) 
#  will return {"err": 0, "res": path to layout.ini} 
#  <br>In case of error the function returns the dictionary value = {"err": message, "res": ""}<br>
#  "err" is string value with error description, "res" is empty string - "".
#  @param path
#  string value = path
#  @param name
#  string value = certain string - for example if string is equal to "layout.ini" - we'll get path to layout.ini file
#  @param log
#  string value = path to file for logging. Default value auto_log.LOG_TO_STDOUT - log to stdout. 
#  Also you can use auto_log.LOG_TO_NONE to disable logging.
#  
## <b>Example:</b>
#  <br>@code
#from auto_utility import file_from_path
#
#result = file_from_path("e:\\Logs", "mylog.xml")
#if result["res"] == "":
#    print("Can't get path to file.")
#else:
#    print("path to mylog.xml = ", result["res"])
#@endcode
def file_from_path(path, name, log = auto_log.LOG_TO_STDOUT):
    id = ID_FILE_FROM_PATH
    #--------------------------------------------------
    result = files_list_from_path(path, name, auto_log.LOG_TO_NONE)
    if result["err"] != 0:
        message = result
        auto_log.write_result(log, message, auto_log.STATUS_ERROR, id)
        result = {"err": message, "res": ""}
        return result
    #--------------------------------------------------
    if result["res"] == []:
        result = {"err": 0, "res": ""}
        return result
    else:
        result = {"err": 0, "res": result["res"][0]}
        return result
#----------------------------------------------------------------------

## <b>Description:</b> The function gets path to startup folder for volume.
#  
#  The function gets path to startup folder for volume.
#  In case of success the function returns string value - path to startup folder.
#  <br>In case of error the function returns empty string - ""
#  @param letter
#  string value = volume letter for searching (for example - y:)
#  @param log
#  string value = path to file for logging. Default value auto_log.LOG_TO_STDOUT - log to stdout. 
#  Also you can use auto_log.LOG_TO_NONE to disable logging.
#  
## <b>Example:</b>
#  <br>@code
#from auto_utility import search_startup_folder
#
#result = search_startup_folder("e:")
#if result == "":
#    print("Can't get path to startup folder for volume " + letter)
#else:
#    path_to_startup = result
#@endcode
def search_startup_folder(letter, log = auto_log.LOG_TO_STDOUT):
    try:
        path = letter + "\\"
        for root, dirs, files in os.walk(path):
            for dir in dirs:
                if dir.endswith("Startup"):
                    line = root + "\\" + dir
                    if re.findall("Users", line):
                        return line
    except:
        return ""
    return ""
#----------------------------------------------------------------------

## <b>Description:</b> The function copies with rewriting *.py and *.pyc files from folder modules_source to folder modules_target.
#  
#  The function copies with rewriting *.py and *.pyc files from folder modules_source to folder modules_target.
#  <br>In case of success the function returns integer value = 0.
#  <br>In case of error the function returns string value with error description.
#  @param modules_source
#  string value = from this folder modules will be copied
#  @param modules_target
#  string value = modules will be copied to this folder.
#  @param log
#  string value = path to file for logging. Default value auto_log.LOG_TO_STDOUT - log to stdout. 
#  Also you can use auto_log.LOG_TO_NONE to disable logging.
#  
## <b>Example:</b>
#  <br>@code
#from auto_utility import copy_python_modules
#
#result = copy_python_modules("e:\\my_modules", "c:\\Python31\\Lib")
#if result != 0:
#    print("Can't copy modules. Error = " + result)
#else:
#    print("Modules are copied successfully.")
#@endcode
def copy_python_modules(modules_source, modules_target, log = auto_log.LOG_TO_STDOUT):
    id = ID_COPY_PYTHON_MODULES
    #--------------------------------------------------
    python_lib_path = modules_target
    result = check_paths_exists([modules_source, python_lib_path])
    if result != 0:
        message = result
        auto_log.write_result(log, message, auto_log.STATUS_ERROR, id)
        return message
    #--------------------------------------------------
    result = files_list_from_path(modules_source, ".py", log)
    if result["err"] != 0:
        message = result["err"]
        auto_log.write_result(log, message, auto_log.STATUS_ERROR, id)
        return message
    py_list = result["res"]
    #--------------------------------------------------
    result = files_list_from_path(modules_source, ".pyc", log)
    if result["err"] != 0:
        message = result["err"]
        auto_log.write_result(log, message, auto_log.STATUS_ERROR, id)
        return message
    pyc_list = result["res"]
    #--------------------------------------------------
    if len(py_list) + len(pyc_list) == 0:
        message = "There are no *.py or *.pyc files in " + modules_source
        auto_log.write_result(log, message, auto_log.STATUS_ERROR, id)
        return message
    #--------------------------------------------------
    for item in py_list:
        try:
            name = python_lib_path + "\\" + item.split("\\")[-1]
            if os.path.exists(name):
                os.remove(name)
            shutil.copy2(item, name)
        except:
            message = "Can't copy " + item
            auto_log.write_result(log, message, auto_log.STATUS_ERROR, id)
            return message
    #--------------------------------------------------
    for item in pyc_list:
        try:
            name = python_lib_path + "\\" + item.split("\\")[-1]
            if os.path.exists(name):
                os.remove(name)
            shutil.copy2(item, name)
        except:
            message = "Can't copy " + item
            auto_log.write_result(log, message, auto_log.STATUS_ERROR, id)
            return message
    #--------------------------------------------------
    return 0
#----------------------------------------------------------------------

## <b>Description:</b> The function copies source folder to target folder.
#  
#  The function copies source folder to target folder. 
#  If target folder exists before copy - it will be deleted first.
#  <br>In case of success the function returns integer value = 0.
#  <br>In case of error the function returns string value with error description.
#  @param sourse
#  string value = source folder
#  @param target
#  string value = target folder.
#  @param log
#  string value = path to file for logging. Default value auto_log.LOG_TO_STDOUT - log to stdout. 
#  Also you can use auto_log.LOG_TO_NONE to disable logging.
#  
## <b>Example:</b>
#  <br>@code
#from auto_utility import copy_folder
#
#result = copy_folder("e:\\my_utils", "y:\\Autotest_utils")
#if result != 0:
#    print("Can't copy folder. Error = " + result)
#else:
#    print("Folder is copied successfully.")
#@endcode
def copy_folder(sourse, target, log = auto_log.LOG_TO_STDOUT):
    id = ID_COPY_FOLDER
    #----------------------------------------------------------------------
    #do nothing for empty source
    if sourse == "":
        return 0
    #----------------------------------------------------------------------
    result = check_paths_exists([sourse])
    if result != 0:
        message = result
        auto_log.write_result(log, message, auto_log.STATUS_ERROR, id)
        return message
    #----------------------------------------------------------------------
    if sourse == target:
        message = "target = " + target + " can't be equal to sourse"
        auto_log.write_result(log, message, auto_log.STATUS_ERROR, id)
        return message
    #----------------------------------------------------------------------
    try:
        if os.path.exists(target):
            shutil.rmtree(target)
    except:
        message = "Can't remove old " + target
        auto_log.write_result(log, message, auto_log.STATUS_ERROR, id)
        return message
    try:
        shutil.copytree(sourse, target)
    except:
        message = "Can't copy " + sourse + " to " + target
        auto_log.write_result(log, message, auto_log.STATUS_ERROR, id)
        return message
    return 0
#----------------------------------------------------------------------

def copy_files_list(files_list, target, log = auto_log.LOG_TO_STDOUT):
    id = ID_COPY_FILES_LIST
    #----------------------------------------------------------------------
    #do nothing for empty source
    if files_list == []:
        return 0
    #----------------------------------------------------------------------
    #check paths
    result = check_paths_exists(files_list)
    if result != 0:
        message = result
        auto_log.write_result(log, message, auto_log.STATUS_ERROR, id)
        return message
    #----------------------------------------------------------------------
    #create empty folder for files
    try:
        if os.path.exists(target):
            shutil.rmtree(target)
    except:
        message = "Can't delete old " + target
        auto_log.write_result(log, message, auto_log.STATUS_ERROR, id)
        return message
    try:
        os.makedirs(target)
    except:
        message = "Can't create empty " + target
        auto_log.write_result(log, message, auto_log.STATUS_ERROR, id)
        return message
    #----------------------------------------------------------------------
    #copy list of files to target folder
    for item in files_list:
        if item != "":
            try:
                if item.count("\\") > 0:
                    shutil.copy2(item, target + "\\" + item.split("\\")[-1])
                else:
                    shutil.copy2(item, target + "\\" + item)
            except:
                message = "Can not copy " + item + " to " + target
                auto_log.write_result(log, message, auto_log.STATUS_ERROR, id)
                return message
    #----------------------------------------------------------------------
    return 0
#----------------------------------------------------------------------

## <b>Description:</b> The function checks if all the paths in the list exist or not.
#  
#  The function checks if all the paths in the list exist or not.
#  <br>In case of all the paths in the list exist the function returns integer value = 0.
#  <br>In other case the function returns string value with error description.
#  @param files
#  list value = list of paths (for example ["c:\\Windows", "c:\\ntdetect.com"])
#  @param log
#  string value = path to file for logging. Default value auto_log.LOG_TO_STDOUT - log to stdout. 
#  Also you can use auto_log.LOG_TO_NONE to disable logging.
#  
## <b>Example:</b>
#  <br>@code
#from auto_utility import check_paths_exists
#
#result = check_paths_exists(["e:\\my_folder", "y:\\test\\my_file.txt"])
#if result != 0:
#    print("Error = " + result)
#else:
#    print("Ok. All the paths from the list exist.")
#@endcode
def check_paths_exists(files, log = auto_log.LOG_TO_STDOUT):
    id = ID_CHECK_PATHS_EXISTS
    #----------------------------------------------------------------------
    try:
        for item in files:
            if item != "":
                if not os.path.exists(item):
                    message = "Can't open " + item
                    auto_log.write_result(log, message, auto_log.STATUS_ERROR, id)
                    return message
    except:
        message = "Can't check files for existence"
        auto_log.write_result(log, message, auto_log.STATUS_ERROR, id)
        return message
    #----------------------------------------------------------------------
    return 0
#----------------------------------------------------------------------

## <b>Description:</b> The function searches on defined volume (<i>letter</i>) the startup folder and creates run.bat file inside it. 
#  The function searches on defined volume (<i>letter</i>) the startup folder and creates run.bat file inside it. 
#  The run.bat file content consists of <i>script</i> file call with parameters defined in <i>parameters</i> string. 
#  The script file itself is copied to auto_utility.AUTOTEST_RUN directory on selected volume <i>letter</i>, 
#  in other words letter + "\\" + auto_utility.AUTOTEST_RUN
#  <br>In case of success the function returns integer value = 0.
#  <br>In case of error the function returns string value with error description.
#  @param script
#  string value = path to script (example: "c:\\my_scripts\\install.py")
#  @param parameters
#  string value = parameters line (example: "hdm.msi") 
#  @param letter
#  string value = volume letter (example: "y:") 
#  @param log
#  string value = path to file for logging. Default value auto_log.LOG_TO_STDOUT - log to stdout. 
#  Also you can use auto_log.LOG_TO_NONE to disable logging.
#  
## <b>Example:</b>
#  <br>@code
#from auto_utility import create_run_bat
#
#result = create_run_bat("c:\\my_scripts\\install.py", "hdm.msi", "y:")
#if result != 0:
#    print("Error = " + result)
#else:
#    print("Ok - run.bat is created successfully.")
#@endcode
def create_run_bat(script, parameters, letter, log = auto_log.LOG_TO_STDOUT):
    id = ID_CREATE_RUN_BAT
    #----------------------------------------------------------------------
    #do nothing for empty input
    if script == "":
        return 0
    #----------------------------------------------------------------------
    result = check_paths_exists([script, letter])
    if result != 0:
        message = result
        auto_log.write_result(log, message, auto_log.STATUS_ERROR, id)
        return message
    #----------------------------------------------------------------------
    #create run.bat in startup folder
    startup_folder = search_startup_folder(letter, log)
    if startup_folder == "":
        message = "Can't find startup folder in " + letter + "\\"
        auto_log.write_result(log, message, auto_log.STATUS_ERROR, id)
        return message
    run_bat = startup_folder + "\\run.bat"
    try:
        file = open(run_bat, "w")
        data = "cd %SYSTEMDRIVE%"+"\\" + AUTOTEST_RUN
        script_name = script.split("\\")[-1]
        if parameters != "":
            data = data + "\n" + '"%s" %s' % (script_name, parameters)
        else:
            data = data + "\n" + '"%s"' % (script_name)
        file.write(data)
        file.close()
    except:
        message = "Can't save file " + run_bat
        auto_log.write_result(log, message, auto_log.STATUS_ERROR, id)
        return message
    #----------------------------------------------------------------------
    #copy script to letter + "\\" + AUTOTEST_RUN
    run_folder = letter + "\\" + AUTOTEST_RUN
    try:
        if os.path.exists(run_folder):
            shutil.rmtree(run_folder)
        os.mkdir(run_folder)
    except:
        message = "Can't create folder " + run_folder
        auto_log.write_result(log, message, auto_log.STATUS_ERROR, id)
        return message
    try:
        script_name = script.split("\\")[-1]
        script_path = run_folder + "\\" + script_name
        shutil.copy2(script, script_path)
    except:
        message = "Can't copy " + script + " to " + script_path
        auto_log.write_result(log, message, auto_log.STATUS_ERROR, id)
        return message
    #----------------------------------------------------------------------
    
    return 0
#----------------------------------------------------------------------

## <b>Description:</b> The function gets system drive letter.
#  The function gets system drive letter.
#  <br>In case of success the function returns dictionary value = {"err": 0, "res": letter}.
#  <br>"err" is integer value = 0, "res" is string value = system drive letter.
#  <br>In case of error the function returns dictionary value = {"err": message, "res": ""}.
#  <br>"err" is string value = error description, "res" is empty string value = "".
#  @param log
#  string value = path to file for logging. Default value auto_log.LOG_TO_STDOUT - log to stdout. 
#  Also you can use auto_log.LOG_TO_NONE to disable logging.
#  
## <b>Example:</b>
#  <br>@code
#from auto_utility import get_system_drive
#
#result = get_system_drive()
#if result["err"] == 0:
#    print("system drive letter = " + result["res"])
#else:
#    print(result["err"])
#@endcode
def get_system_drive(log = auto_log.LOG_TO_STDOUT):
    id = ID_GET_SYSTEM_DRIVE
    #----------------------------------------------------------------------
    result = auto_log.get_cmd_output("echo %SYSTEMDRIVE%")
    if result["err"] != 0:
        message = "Can't get system drive letter, using command echo %SYSTEMDRIVE%"
        message = message + "\nerror code = " + str(result["err"])
        auto_log.write_result(log, message, auto_log.STATUS_ERROR, id)
        result = {"err": message, "res": ""}
        return result
    else:
        letter = result["out"][0:2]
        result = {"err": 0, "res": letter}
        return result
#----------------------------------------------------------------------

## <b>Description:</b> The function adds certificate to localMachine TrustedPublisher.
#  The function adds certificate to localMachine TrustedPublisher.
#  <br>In case of success the function returns integer value = 0.
#  <br>In case of error the function returns string value = error description.
#  @param certmgr
#  string value = path to CertMgr.Exe (special utility from Microsoft)
#  @param certificate
#  string value = path to certificate file (*.cer)
#  @param log
#  string value = path to file for logging. Default value auto_log.LOG_TO_STDOUT - log to stdout. 
#  Also you can use auto_log.LOG_TO_NONE to disable logging.
#  
## <b>Example:</b>
#  <br>@code
#from auto_utility import add_certificate
#
#result = add_certificate("c:\\certmgr.exe", "c:\\paragon.cer")
#if result == 0:
#    print("Certificate is added successfully")
#else:
#    print(result)
#@endcode
def add_certificate(certmgr, certificate, log = auto_log.LOG_TO_STDOUT):
    id = ID_ADD_CERTIFICATE
    #----------------------------------------------------------------------
    result = get_system_drive()
    if result["err"] != 0:
        message = result["err"]
        auto_log.write_result(log, message, auto_log.STATUS_ERROR, id)
        return message
    system_drive = result["res"]
    #----------------------------------------------------------------------
    if not os.path.exists(system_drive + "\\windows\\system32\\slmgr.vbs"):
        return 0
    #----------------------------------------------------------------------
    result = check_paths_exists([certmgr, certificate])
    if result != 0:
        message = result
        auto_log.write_result(log, message, auto_log.STATUS_ERROR, id)
        return message
    #----------------------------------------------------------------------
    add_cert = '"%s" -add "%s" -c -s -r localMachine TrustedPublisher' % (certmgr, certificate)
    result = auto_log.get_cmd_output2(add_cert)
    if result["err"] != 0:
        message = "Cant add certificate " + certificate + " to localMachine TrustedPublisher"
        message = message + "\n" + "certmgr.exe error code = " + str(result["err"])
        message = message + "\n" + "certmgr.exe error output = " + str(result["out"])
        auto_log.write_result(log, message,  auto_log.STATUS_ERROR, id)
        return message
    #----------------------------------------------------------------------
    return 0
#----------------------------------------------------------------------

## <b>Description:</b> The function runs list of diskpart commands.
#  The function runs list of diskpart commands.
#  <br>In case of success the function returns integer value = 0.
#  <br>In case of error the function returns string value = error description.
#  @param commands
#  list value = commands for diskpart (example: ["select volume 2", "delete"])
#  @param log
#  string value = path to file for logging. Default value auto_log.LOG_TO_STDOUT - log to stdout. 
#  Also you can use auto_log.LOG_TO_NONE to disable logging.
#  
## <b>Example:</b>
#  <br>@code
#from auto_utility import call_diskpart
#
#result = call_diskpart(["select volume 2", "delete"])
#if result != 0:
#    print(result)
#else:
#    print("volume 2 is successfully deleted")
#@endcode
def call_diskpart(commands, log = auto_log.LOG_TO_STDOUT):
    id = ID_CALL_DISKPART
    #--------------------------------------------------
    path_name = "diskpart" + str(time.time())
    #--------------------------------------------------
    try:
        data = ""
        for item in commands:
            data = data + item + "\n"
        file = open(path_name, "w")
        file.write(data)
        file.close()
    except:
        message = "Can't create script file for diskpart"
        auto_log.write_result(log, message,  auto_log.STATUS_ERROR, id)
        return message
    #--------------------------------------------------
    command = 'diskpart /s %s' % (path_name)
    result = auto_log.get_cmd_output2(command)
    #--------------------------------------------------
    stop = 0
    while stop != 1:
        try:
            os.remove(path_name)
            stop = 1
        except:
            time.sleep(5)
    #--------------------------------------------------
    if result["err"] != 0:
        message = "call diskpart failed with \nerror = " + str(result["err"])
        auto_log.write_result(log, message,  auto_log.STATUS_ERROR, id)
        return message
    return 0
#----------------------------------------------------------------------

## <b>Description:</b> The function changes key in hdm layout.ini file.
#  The function changes key in hdm layout.ini file.
#  <br>In case of success the function returns integer value = 0.
#  <br>In case of error the function returns string value = error description.
#  @param path
#  string value = path to layout.ini (example: "C:\\Program Files (x86)\\Paragon Software\\HDM Internal\\layout.ini")
#  @param key
#  string value = key in layout.ini (example: "Write logs into Bluescrn")
#  @param value
#  string value = value for key in layout.ini (example: "on")
#  @param log
#  string value = path to file for logging. Default value auto_log.LOG_TO_STDOUT - log to stdout. 
#  Also you can use auto_log.LOG_TO_NONE to disable logging.
#  
## <b>Example:</b>
#  <br>@code
#from auto_utility import hdm_change_layout_ini_key
#
#path = "C:\\Program Files (x86)\\Paragon Software\\HDM Internal\\layout.ini"
#result = hdm_change_layout_ini_key(path, "Write logs into Bluescrn", "on")
#if result != 0:
#    print(result)
#else:
#    print("layout.ini is updated successfully!")
#@endcode
def hdm_change_layout_ini_key(path, key, value, log = auto_log.LOG_TO_STDOUT):
    id = ID_HDM_CHANGE_LAYOUT_INI_KEY
    #--------------------------------------------------
    lines = []
    #--------------------------------------------------
    try:
        if os.path.exists(path):
            file = open(path, "r")
            bool_go = 1
            while bool_go:
                line = file.readline()
                if line == "":
                    bool_go = 0
                else:
                    words = line.split(" = ")
                    if words[0] != key:
                        if line != "\n":
                            lines.append(line)
            
            file.close()
    except:
        message = "Can not read " + path
        auto_log.write_result(log, message,  auto_log.STATUS_ERROR, id)
        return message
    #--------------------------------------------------
    try:
        lines.append('\n%s = %s' % (key, value))
        
        file = open(path, "w")
        data = ""
        for line in lines:
            data = data + line
        file.write(data)
        file.flush()
        file.close()
    except:
        message = "Can not update " + path
        auto_log.write_result(log, message,  auto_log.STATUS_ERROR, id)
        return message
    #--------------------------------------------------
    return 0
#----------------------------------------------------------------------
